<?php

class FormElement
{

  /**
   * @var int
   */
  public $actions = Form::ACTION_ALL;

  /**
   * @var boolean
   */
  public $enabled = true;

  /**
   * @var string
   */
  public $field;

  /**
   * @var Form
   */
  public $form;

  /**
   * @var string
   */
  public $name;

  /**
   * @var string
   */
  public $rules;

  /**
   * @var string
   */
  public $title;

  /**
   * @var FilterChain
   */
  protected $filterChain;

  /**
   * Constructor.
   *
   * @param string $name the element's name
   * @param string $title the element's title
   * @return void
   */
  public function __construct($name, $title = null)
  {
    $this->name = $name;
    $this->title = $title;
  }

  /**
   *
   * @return string the element's name
   */
  public function getName()
  {
    return $this->name;
  }

  /**
   *
   * @return string the element's title
   */
  public function getTitle()
  {
    if (is_null($this->title)) {
      $this->title = Inflector::titleize($this->getName());
    }

    return $this->title;
  }

  /**
   *
   * @return string the element's database field
   */
  public function getField()
  {
    if (empty($this->field)) {
      $this->field = Inflector::underscore($this->getName());
    }

    return $this->field;
  }

  protected function getDisplayValue(&$row)
  {
    return $this->getValue($row);
  }

  protected function getValue(&$row)
  {
    return $row[$this->getField()];
  }

  protected function setValue(&$row, $value)
  {
    $row[$this->getField()] = $value;
  }

  protected function getFieldValue(&$row, $name)
  {
    return $row[$name];
  }

  /**
   *
   * @return FilterChain
   */
  public function filters($hook = null)
  {
    if (empty($this->filterChain)) {
      $this->filterChain = new FilterChain();
    }

    if (func_num_args()) {
      return call_user_func_array(array($this->filterChain, 'call'), func_get_args());
    }

    return $this->filterChain;
  }

  public function getClass(&$row, $action)
  {
    $class = array('form-element', $this->getTypeClass(), $this->getInstanceClass());

    if ($action != Form::ACTION_CREATE) {
      $class[] = $this->getRowClass($row);
    }

    $class = implode(' ', $class);

    return $class;
  }

  public function getTypeClass()
  {
    $class = get_class($this);
    return $this->classify($class);
  }

  public function getInstanceClass()
  {
    $class = get_class($this) . ' ' . $this->name;
    return $this->classify($class);
  }

  public function getRowClass(&$row)
  {
    $class = get_class($this) . ' ' . $this->name . ' ' . $this->getFieldValue($row, $this->form->getPk());
    return $this->classify($class);
  }

  public function classify($class)
  {
    return str_replace('_', '-', Inflector::underscore($class));
  }

  public function inAction($action)
  {
    return ($this->actions & $action) == $action;
  }

  public function setDataFromPost(&$row, $post, $action)
  {
    $this->setValue($row, $post->get($this->getField()));
  }

  public function beforeRender($row, $action)
  {
    $this->filters('before_render', $row, $action);
  }

  public function render($row, $action)
  {
    $this->beforeRender($row, $action);

    switch ($action) {
      case Form::ACTION_INDEX :
        $output = $this->getDisplayValue($row);

        break;

      case Form::ACTION_VIEW :
        $value = $this->getDisplayValue($row);

        $output = '<span class="'.$this->getClass($row, $action).'"><label>'.$this->getTitle().':</label> <span class="form-element-body">'.$value.'</span></span>';

        break;

      default :
        $view = $this->getView($action);

        $view->set('value', $this->getValue($row));
        $view->set('class', $this->getClass($row, $action));

        $output = $view->render();
    }

    $output = $this->afterRender($output, $row, $action);

    return $output;
  }

  public function afterRender($output, $row, $action)
  {
    return $this->filters('after_render', $output, $row, $action);
  }

  /**
   *
   * @param string $action
   * @param string $type
   * @return View
   */
  protected function getView($action, $type = 'PHP')
  {
    if (empty($this->view)) {
      $this->view = View::factory($type);

      $this->view->set('action', $action);
      $this->view->set('name', $this->name);
      $this->view->set('title', $this->title);
      $this->view->set('typeClass', $this->getTypeClass());
      $this->view->set('instanceClass', $this->getInstanceClass());
      $this->view->set('enabled', $this->enabled);

      $this->view->setTemplate($this->getTemplate($action));
    }

    return $this->view;
  }

  protected function getTemplate($action)
  {
    global $config;

    return $config['views_dir'] . '/form/' . Inflector::underscore(get_class($this)) . '_view.php';
  }

}

?>